#include<iostream>
#include<string>
#include<cstring>
#include<cerrno>
#include<sys/socket.h>
#include<sys/types.h>
#include<arpa/inet.h>
#include<netinet/in.h>
#include<unistd.h>
#include<pthread.h>
#include<signal.h>
#include<sys/wait.h>
#include"Task.hpp"
#include"thread_pool.hpp"

using namespace std;
using namespace  ns_threadpool;
using namespace  ns_task;
string Usage(string proc)
{
    cout<<"Usage"<<proc<<"prot"<<endl;
}


// void ServiceIO(int new_sock)
// {
//     while(1)
//     {
//         char buffer[1024];
//         memset(buffer,0,sizeof(buffer));
//         size_t s=read(new_sock,buffer,sizeof(buffer)-1);
//         if(s>0){
//             buffer[s]=0;
//             cout<<"client#:"<<buffer<<endl;
//             string echo_string="server--";
//             echo_string +=buffer;
//             write(new_sock,echo_string.c_str(),echo_string.size());          
//         }
//         else if(s==0) 
//         {
//             cout<<"client quit!!"<<endl;break;
//         }
      
//         else
//         {
//             cerr<<"read error"<<endl;break;
//         } 
        
//     }
// }

// ./tcp_server prot
int main(int argc,char* argv[])
{
    if(argc!=2){
        Usage(argv[1]); return 1;
    }

    //1.创建套接字
    int listen_sock=socket(AF_INET,SOCK_STREAM,0);
    if(listen_sock<0)
    {
        cerr<<"socktet error"<<errno<<endl; return 2;
    }

    //2.bind
    struct sockaddr_in local;
    local.sin_family=AF_INET;
    local.sin_addr.s_addr=INADDR_ANY;
    local.sin_port=htons(atoi(argv[1]));

    if(bind(listen_sock,(struct sockaddr*)&local,sizeof(local))<0)
    {
        cerr<<"bind error"<<errno<<endl; return 3;
    }

    //3.链接
    //套接字设置listen状态本质是:不断的给用户提供一个建立连接的功能
    const int back_log=3;//back_log -的挂起连接队列可能增长到的最大长度
    if(listen(listen_sock,back_log)<0)
    {
        cerr<<"listen error"<<endl; return 4;
    }

   // signal(SIGCHLD,SIG_IGN);//在Linux中父进程忽略子进程的SIGCHLD信号，子进程会自动退出释放资源
    for(;;)
    {
        struct sockaddr_in peer;
        socklen_t len=sizeof(peer);
        int new_sock=accept(listen_sock,(struct sockaddr*)&peer,&len);
        if(new_sock<0) continue;
        //ServiceIO(new_sock); 单线程版本没人用

        uint16_t cli_port=ntohs(peer.sin_port); //网络转主机序列
        string cli_ip=inet_ntoa(peer.sin_addr);//主机地址(以网络字节顺序给出)转换为
                                               //IPv4点分十进制格式的字符串

        cout<<"get a new link: "<<cli_port<<"-"<<cli_ip<<endl;

        Task t(new_sock);
        ThreadPool<Task>::GetInstance()->PushTask(t);
        // pid_t id=fork();
        // if(id<0){
        //     continue;
        // }
        // //父进程打开的fd子进程会继承下去,父子进程中的哪个都要关闭不用的文件描述符
        // else if(id==0)// child
        // {
        //     close(listen_sock);

        //     //用这个不需要等待
        //     //退出的是子进程,子进程刚创建出来就退出了
        //     if(fork()>0)exit(0);

        //     //向后走的是孙子进程,爷孙进程不需要等待
        //     ServiceIO(new_sock);
        //     close(new_sock);//不关闭文件描述符,会造成文件描述符泄漏的问题
        //     exit(0);
        // }
        // else//father
        // { 
        //     waitpid(id,nullptr,0); //等待子进程
        //     close(new_sock);
        // }
    }
    return 0;
}